package com.vhall.component.service.interactive.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.entity.interactive.dto.QuestionAnswerNumberCacheDTO;
import com.vhall.component.entity.interactive.dto.QuestionAnswerRefCacheDTO;
import com.vhall.component.entity.interactive.vo.QuestionCountVo;
import com.vhall.component.entity.interactive.vo.QuestionListDTO;
import com.vhall.component.entity.interactive.vo.QuestionListQuery;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.framework.common.utils.StringUtils;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.utils.Base64Coding;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.service.interactive.QuestionCacheService;
import com.vhall.component.service.interactive.assembler.QuestionAssembler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author yuanzh
 */

@Slf4j
@Service
public class QuestionCacheServiceImpl implements QuestionCacheService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private QuestionAssembler questionAssembler;

    @Override
    public String getWatchSideHashKey(QuestionListQuery req) {
        return Base64Coding
                .encode(String.valueOf(req.getPage()) + req.getPageSize() + req.getKeyword() + req.getPublish() + req.getIsPublic()
                        + req.getBeginDate() + req.getEndDate());
    }

    @Override
    public void cacheWatchSideQuestionData(String roomId, String hashKey, Page<QuestionListDTO> pageData) {
        String cacheKey = RedisKey.WATCH_SIDE_QUESTION_DATA_CACHE_PRE_KEY + roomId;
        BoundHashOperations hashOps = stringRedisTemplate.boundHashOps(cacheKey);
        hashOps.put(hashKey, JsonUtil.toJsonString(pageData));
        // 设置随机3～5秒有效期
        hashOps.expire((int) (3 + Math.random() * (5 - 3 + 1)), TimeUnit.SECONDS);
    }

    @Override
    public Page<QuestionListDTO> getCachedData(String roomId, String hashKey) {
        String cacheKey = RedisKey.WATCH_SIDE_QUESTION_DATA_CACHE_PRE_KEY + roomId;
        Object cachedObj = stringRedisTemplate.opsForHash().get(cacheKey, hashKey);
        if (Objects.isNull(cachedObj)) {
            return null;
        }
        Page page = JsonUtil.objectFromJSONString(cachedObj.toString(), Page.class);
        page.setRecords(JsonUtil.arrayFromJSONString(JsonUtil.toJsonString(page.getRecords()), QuestionListDTO.class));
        return page;
    }

    @Override
    public void deleteCachedQuestionDetailData(String roomId) {
        if (StringUtils.isNotEmpty(roomId)) {
            redisTemplate.delete(RedisKey.WATCH_SIDE_QUESTION_DATA_CACHE_PRE_KEY + roomId);
        }
    }

    @Override
    public String getQuestionAnswerNumberCacheKey(String roomId) {
        return RedisKey.QUESTION_ANSWER_NUMBER_CACHE_PRE_KEY + roomId;
    }

    @Override
    public void cacheQuestionAnswerNumber(String roomId, List<QuestionAnswerNumberCacheDTO> cacheList) {
        BoundHashOperations hashOps = redisTemplate.boundHashOps(getQuestionAnswerNumberCacheKey(roomId));
        HashMap<String, String> map = new HashMap<>(8);
        for (QuestionAnswerNumberCacheDTO cacheDTO : cacheList) {
            map.put(String.valueOf(cacheDTO.getQuestionId()), JsonUtil.toJsonString(cacheDTO));
        }
        hashOps.putAll(map);
        // 设置随机3～5秒有效期
        hashOps.expire((int) (3 + Math.random() * (5 - 3 + 1)), TimeUnit.SECONDS);
    }

    @Override
    public void deleteCachedQuestionAnswerRef(String roomId, String accountId) {
        if (StringUtils.isNotEmpty(roomId) && StringUtils.isNotEmpty(accountId)) {
            redisTemplate.opsForHash().delete(getUserQuestionAnswerRefCacheKey(roomId), accountId);
        }
    }

    @Override
    public String getUserQuestionAnswerRefCacheKey(String roomId) {
        return RedisKey.QUESTION_USER_LATEST_ANSWER_REF_CACHE_PRE_KEY + roomId;
    }

    @Override
    public void cacheUserQuestionAnswerRef(String roomId, Integer accountId, List<QuestionAnswerRefCacheDTO> cacheList) {
        BoundHashOperations hashOps = redisTemplate.boundHashOps(getUserQuestionAnswerRefCacheKey(roomId));
        hashOps.put(String.valueOf(accountId), JsonUtil.toJsonString(cacheList));
        // 设置随机3～5秒有效期
        hashOps.expire(1, TimeUnit.SECONDS);
    }

    @Override
    public List<QuestionCountVo> listCachedQuestionAnswerNumber(String roomId, List<Integer> questionIds) {
        List dataList = redisTemplate.opsForHash().multiGet(getQuestionAnswerNumberCacheKey(roomId),
                questionIds.stream().map(String::valueOf).collect(Collectors.toSet()));
        dataList = (List) dataList.stream().filter(Objects::nonNull).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(dataList)) {
            return Collections.emptyList();
        }
        return questionAssembler.convertQuestionAnswerNumberCacheTo(
                JsonUtil.arrayFromJSONString(dataList.toString(), QuestionAnswerNumberCacheDTO.class));
    }

    @Override
    public List<QuestionCountVo> listCachedQuestionAnswerRef(String roomId, Integer accountId, List<Integer> questionIds) {
        Object cacheObj = redisTemplate.opsForHash().get(getUserQuestionAnswerRefCacheKey(roomId), String.valueOf(accountId));
        if (Objects.isNull(cacheObj)) {
            return Collections.emptyList();
        }
        return questionAssembler
                .convertQuestionAnswerCacheTo(JsonUtil.arrayFromJSONString(cacheObj.toString(), QuestionAnswerRefCacheDTO.class));
    }

}
